﻿using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

namespace Soul.IdentityServer.Endpoints
{
    public class TokenEndpoint : EndpointBase
    {
        private readonly IClientStore _clientStore;
        private readonly ITokenService _tokenService;
        private readonly IScopeValidator _scopeValidator;
        private readonly IGrantValidatorFactory _grantService;
        private readonly IClientSecretValidator _secretValidator;

        public TokenEndpoint(IClientStore clientStore, ITokenService tokenService, IScopeValidator scopeValidator, IGrantValidatorFactory grantService, IClientSecretValidator secretValidator)
        {
            _clientStore = clientStore;
            _tokenService = tokenService;
            _scopeValidator = scopeValidator;
            _grantService = grantService;
            _secretValidator = secretValidator;
        }

        public override async Task<EndpointResult> HandleAsync(HttpContext context)
        {
            if (!HttpMethods.IsPost(context.Request.Method))
            {
                throw new ValidationException(ValidationErrors.InvalidRequestMethod, "Method not allowed");
            }
            if (!context.IsFormContentRequest())
            {
                throw new ValidationException(ValidationErrors.InvalidRequestContentType, "Content type not allowed");
            }
            var parameters = new OpenIdConnectParameters(context.Request.Form);
            var client = await _secretValidator.ValidationAsync(parameters); ;
            var resources = await _scopeValidator.ValidationAsync(client, parameters);
            var tokenGrantcontext = new TokenGrantContext(client, resources, new ClaimsPrincipal(), parameters);
            await _grantService.ValidateAsync(tokenGrantcontext);
            var accessToken = await _tokenService.CreateAccessTokenAsync(tokenGrantcontext);
            var responses = new OpenIdConnectResponses
            {
                { OpenIdConnectParameterNames.Scope, resources.Scopes },
                { OpenIdConnectParameterNames.AccessToken, accessToken }
            };
            return JsonResult(responses);
        }

    }
}
